var net = require('net');
var qqwry = null;
var redisHelper = require('./helper/redisHelper.js');
redisHelper = new redisHelper();

var config = require('./config/config.js');

var port = process.env.PORT2 || 8868;

// 捕捉全局异常
process.on('uncaughtException', function(err) {
  console.error(err);
});

//############# session ##################
var socket = require('./connector.js');
var server = net.createServer(socket.session);

server.on('error', function(error) {
  console.log('server error: ');
  console.error(error);
  if (error.code == 'EADDRINUSE') {
    console.log('port: %s, Address in use, retrying...', port);
    /*server.listen(6878, function(){
      console.log('socket server bound again, port:6878.');
    });*/
  }
});
// 当服务被关闭时触发. 注意：如果当前仍有活动连接,将等到所有连接都结束后才触发。
server.on('close', function() {
  console.log('server closed....');
  // 自动重启，删除所有redis缓存Socket队列
  // server.listen(6868, function() {
  //  console.log('socket server bound again, port:8868.');
  // });
});

server.listen(port, function() {
  console.log('instant-session is up on %s', port);
});

//############# webservice ##################
var express = require('express');
var ws = express();
ws.enable('trust proxy'); // 允许反向代理 --> ws.set('trust proxy', true);
ws.set('port', process.env.PORT1 || 8869);

ws.use(express.bodyParser());
ws.use(express.errorHandler());
// 防止爬虫
ws.all('/instant/authenticate', blackList, preventSpider);

// ############# auth ##################
require('./auth.js')(ws, redisHelper, config);
// ############# api ##################
require('./dispatch.js')(ws, socket.connections, qqwry, config);

// 中间件错误处理：当next(err)就会多一个参数，自然到这个责任链
ws.use(function(err, req, res, next) {
  res.status(err.status || 500);
  res.send({
    error: err.message
  });
});

ws.listen(ws.get('port'));
console.log('instant-webservice is up --> port：%s', ws.get('port'));


var thresholdVal = 100;
var thresholdTime = 10 * 60 * 1000;

/** 检测是否属于黑名单之中
 *
 * [blackList description]
 * @param  {[type]}   req  [description]
 * @param  {[type]}   res  [description]
 * @param  {Function} next [description]
 * @return {[type]}        [description]
 */
function blackList(req, res, next) {
  var ip = req.ip;
  console.log('开始检测ip：%s 是否合法!', ip);

  redisHelper.get(ip, function(err, reply) {
    if (!err && reply) { // 存在黑名单
      console.log('%s 请求过于频繁！已加入黑名单，10分钟后解除!', ip);
      next(new Error('请求过于频繁！已加入黑名单，10分钟后解除!'));
    } else if (!err && !reply) {
      next();
    } else {
      next(err);
    }
  });
}

/** 防止爬虫恶意请求，导致单线程不能处理业务
 *  策略：
 *    1.10分钟之内相同ip过度请求，加入黑名单(持续10分钟)
 *    2.拦截黑名单内ip恶意请求
 *
 * [preventSpider description]
 * @param  {[type]}   req  [description]
 * @param  {[type]}   res  [description]
 * @param  {Function} next [description]
 * @return {[type]}        [description]
 */
function preventSpider(req, res, next) {
  console.log('开始监控ip：%s 请求!', req.ip);

  redisHelper.hget('prevent_spider', req.ip, function(err, reply) {
    if (!err && !reply) { // 第一次访问
      var counter = {
        count: 0,
        modifyTime: Date.now(),
        createTime: Date.now()
      };
      redisHelper.hset('prevent_spider', req.ip, JSON.stringify(counter), 'forever', function(err, reply) {
        if (!err) {
          next();
        } else {
          next(err);
        }
      });
    } else if (!err && reply) { // 根据策略检测，比较阀值加入黑名单
      var obj = JSON.parse(reply);
      obj.count = obj.count + 1;
      obj.modifyTime = Date.now();
      if ((obj.modifyTime - obj.createTime >= thresholdTime) && (obj.count >= thresholdVal)) {
        // 加入黑名单，并且重置状态
        redisHelper.set(req.ip, req.ip, 600, function(err, reply) {
          if (!err) {
            redisHelper.hdel('prevent_spider', req.ip, function(err, reply) {
              if (!err) {
                next(new Error('频繁恶意请求！已加入黑名单，10分钟后解除!'));
              } else {
                next(err);
              }
            });
          }
        });
      } else if ((obj.modifyTime - obj.createTime >= thresholdTime) && (obj.count < thresholdVal)) {
        // 重置黑名单状态
        redisHelper.hdel('prevent_spider', req.ip, function(err, reply) {
          if (!err) {
            next();
          } else {
            next(err);
          }
        });
      } else {
        redisHelper.hset('prevent_spider', req.ip, JSON.stringify(obj), 'forever', function(err, reply) {
          if (!err) {
            next();
          } else {
            next(err);
          }
        });
      }
    }
  });
}
